package com.muyangren.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.muyangren.constants.EsConstant;
import com.muyangren.entity.EsTransMap;
import com.muyangren.entity.TransEsContent;
import com.muyangren.entity.TransEsSearch;
import com.muyangren.service.ElasticService;
import com.muyangren.utils.ElasticSearchUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.io.IOException;
import java.rmi.ServerException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: muyangren
 * @Date: 2023/1/29
 * @Description: com.muyangren.service.impl
 * @Version: 1.0
 */
@Service
public class ElasticServiceImpl implements ElasticService {

    @Resource
    private ElasticsearchClient esClient;
    @Value("${elasticsearch.analyzer}")
    private String analyzer;
    @Value("${elasticsearch.index}")
    private String index;
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Boolean initEsData() {
        //1)初始化数据前先确保索引已创建
        Boolean aBoolean = Boolean.FALSE;
        try {
            aBoolean = ElasticSearchUtils.whetherIndex(esClient, index, analyzer);
            if (Boolean.FALSE.equals(aBoolean)) {
                throw new ServerException("ES服务器未启动！");
            }
            //2)获取数据(实际项目中是通过sql查询出来的)
            List<TransEsContent> transEsContentList = new ArrayList<>();
            int num = 20;
            for (int i = 0; i < num; i++) {
                TransEsContent transEsContent = new TransEsContent();
                transEsContent.setId(i);
                transEsContent.setTitle("num标题" + i);
                transEsContent.setType(1);
                transEsContent.setContent("中华人民共和国" + i);
                transEsContent.setCreateTimeLong(System.currentTimeMillis());
                transEsContent.setCreateTime(sdf.format(new Date()));
                transEsContentList.add(transEsContent);
            }
            int num2 = 40;
            for (int j = 21; j < num2; j++) {
                TransEsContent transEsContent = new TransEsContent();
                transEsContent.setId(j);
                transEsContent.setTitle("num2标题" + j);
                transEsContent.setType(2);
                transEsContent.setContent("测试共和国测试测试共和国测试测试共和国测试人民" + j);
                transEsContent.setCreateTimeLong(System.currentTimeMillis());
                transEsContent.setCreateTime(sdf.format(new Date()));
                transEsContentList.add(transEsContent);
            }
            int num3 = 60;
            for (int k = 41; k < num3; k++) {
                TransEsContent transEsContent = new TransEsContent();
                transEsContent.setId(k);
                transEsContent.setTitle("num3标题" + k);
                transEsContent.setType(3);
                transEsContent.setContent("人民共和国测试用例数据" + k);
                transEsContent.setCreateTimeLong(System.currentTimeMillis());
                transEsContent.setCreateTime(sdf.format(new Date()));
                transEsContentList.add(transEsContent);
            }
            int num4 = 80;
            for (int q = 61; q < num4; q++) {
                TransEsContent transEsContent = new TransEsContent();
                transEsContent.setId(q);
                transEsContent.setTitle("num4标题" + q);
                transEsContent.setType(3);
                transEsContent.setContent("完全不沾边的数据,但不完全不沾边【人民】" + q);
                transEsContent.setCreateTimeLong(System.currentTimeMillis());
                transEsContent.setCreateTime(sdf.format(new Date()));
                transEsContentList.add(transEsContent);
            }
            Long aLong = ElasticSearchUtils.addAllEsTransfer(esClient, transEsContentList, index);
            if (aLong ==null){
                aBoolean=Boolean.FALSE;
            }
        } catch (ServerException e) {
            e.printStackTrace();
        }
        return aBoolean;
    }

    @Override
    public Boolean addEsTrans(TransEsContent transEsContent) {
        transEsContent.setCreateTimeLong(System.currentTimeMillis());
        transEsContent.setCreateTime(sdf.format(new Date()));
        ElasticSearchUtils.addEsTransfer(esClient, transEsContent, index);
        return true;
    }

    @Override
    public Boolean delEsTrans(Integer id) {
        return ElasticSearchUtils.asyncDelEsTransfer(id, esClient, index);
    }

    @Override
    public Boolean updateEsTrans(TransEsContent transEsContent) {
        ElasticSearchUtils.updateEsTransfer(transEsContent, esClient, index);
        return true;
    }

    @Override
    public EsTransMap selectEsTransPage(TransEsSearch transEsSearch) {
        //记录搜索时间
        StopWatch sw = new StopWatch();
        sw.start();
        //处理分页
        int current;
        if (transEsSearch.getPageNo() < 1) {
            transEsSearch.setPageNo(1);
        }
        if (transEsSearch.getPageSize() < 1) {
            transEsSearch.setPageSize(10);
        }
        if (transEsSearch.getPageNo() == 1) {
            current = transEsSearch.getPageNo() - 1;
        } else {
            current = (transEsSearch.getPageNo() - 1) * transEsSearch.getPageSize();
        }

        //处理关键字的特殊符号
        String regEx = "[\n`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。， 、？]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(transEsSearch.getKeyword());
        transEsSearch.setKeyword(m.replaceAll("").trim());

        //添加过滤条件
        SearchRequest.Builder builder = new SearchRequest.Builder();
        SearchRequest specificContent;

        specificContent = builder
                .index(index)
                .query(q -> q
                        .bool(b -> {
                            try {
                                //1)关键字搜索
                                b.must(t -> t.match(v -> v.field(EsConstant.CONTENT).query(FieldValue.of(transEsSearch.getKeyword()))));
                                //2）时间范围查询
                                //2.1)初始化查询时间
                                long beginDateMillis = sdf.parse(EsConstant.MIN_SEARCH_DATE).getTime();
                                long endDateMillis = System.currentTimeMillis();
                                //2.2)查询过滤时间
                                if (transEsSearch.getBeginDate() != null) {
                                    beginDateMillis = sdf.parse(transEsSearch.getBeginDate()).getTime();
                                }
                                if (transEsSearch.getEndDate() != null) {
                                    endDateMillis = sdf.parse(transEsSearch.getEndDate()).getTime();
                                }
                                Long finalBeginDateMillis = beginDateMillis;
                                Long finalEndDateMillis = endDateMillis;
                                b.filter(f -> f.range(r -> r.field(EsConstant.CREATE_TIME_LONG).gte(JsonData.of(finalBeginDateMillis)).lte(JsonData.of(finalEndDateMillis))));
                                //3)类型搜索
                                Integer type = transEsSearch.getType();
                                if (type != null) {
                                    b.must(t -> t.match(v -> v.field(EsConstant.TYPE).query(FieldValue.of(type))));
                                }
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
                            return b;
                        })
                )
                //高亮
                .highlight(h -> h.fields(EsConstant.CONTENT, f -> f.preTags("<font color='red'>").postTags("</font>")))
                //时间倒序
                .sort(sort -> sort.field(f -> f.field(EsConstant.CREATE_TIME_LONG).order(SortOrder.Desc)))
                //从第from开始每次查询size个(第一条数据下标为0)
                .from(current)
                .size(transEsSearch.getPageSize())
                .build();

        SearchResponse<TransEsContent> searchResponse;
        EsTransMap esTransMap = new EsTransMap();
        try {
            searchResponse = esClient.search(specificContent, TransEsContent.class);
            List<TransEsContent> transEsList = new ArrayList<>();
            List<Hit<TransEsContent>> hits = searchResponse.hits().hits();
            if (!hits.isEmpty()) {
                handleContent(hits, transEsList);
            }
            sw.stop();
            esTransMap.setRecords(transEsList);
            esTransMap.setQueryTime(sw.getTotalTimeMillis());
            esTransMap.setTotal(searchResponse.hits().total().value());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return esTransMap;
    }

    /**
     * 替换文本内容
     * @param hits
     * @param transEsList
     * @return
     */
    private List<TransEsContent> handleContent(List<Hit<TransEsContent>> hits, List<TransEsContent> transEsList) {
        for (Hit<TransEsContent> hit : hits) {
            TransEsContent source = hit.source();
            Map<String, List<String>> highlight = hit.highlight();
            if (highlight != null) {
                //高亮内容
                List<String> highlightList = highlight.get(EsConstant.CONTENT);
                if (highlightList.size() == 1) {
                    source.setHighlightContent(highlightList.get(0));
                } else {
                    //todo 待优化处理多个高亮内容的多个关键字。
                    //for (String keyWords : highlightList) {
                    //    final Pattern pattern;
                    //    pattern = Pattern.compile("<font color='red'>(.*?)</font>");
                    //    Matcher matcher = pattern.matcher(keyWords);
                    //    boolean hasPic = matcher.find();
                    //    if (hasPic) {
                    //        String group = matcher.group(1);
                    //        String replaceContent = source.getContent().replace(group, "<font color='red'>" + group + "</font>");
                    //        source.setContent(replaceContent);
                    //    }
                    //}
                }
            }
            transEsList.add(source);
        }
        return transEsList;
    }

    //public static void main(String[] args) {
    //  String content = "哈哈哈哈<font color='red'>基尼太美</font>222222";
    //    Pattern p = Pattern.compile("<font color='red'>(.*?)</font>");
    //    Matcher matcher = p.matcher(content);
    //    boolean hasPic = matcher.find();
    //    if (hasPic) {
    //        System.out.println(matcher.group(1));
    //    }
    //}
}
